import { Context } from '../types'

export const ErrorReason = {
  UniqueConstraintError: 'UniqueConstraintError',

  UserValidatedError: 'UserValidatedError',
  UserNotExistError: 'UserNotExistError',

  OverPermission: 'OverPermission',
}

const Reasons = {
  // unique 字段重复
  UniqueConstraintError: {
    Code: 401,
    Msg: `Error reason: duplicate.`,
  },
  UserValidatedError: {
    Code: 403,
    Msg: `Error reason: user not legal.`,
  },
  UserNotExistError: {
    Code: 404,
    Msg: `Error reason: user not exist.`,
  },
  OverPermission: {
    Code: 403,
    Msg: `Error reason: cant operate others' info.`,
  },
}

function generateErrorReason(error: string) {
  const reasons = Object.keys(Reasons)
  for (const rs of reasons) {
    if (error.includes(rs)) {
      return Reasons[rs]
    }
  }
  return {
    Code: 400,
    Msg: `Error reason: ${error}.`,
  }
}

/**
 * @description 验证参数存在性
 * @param ctx
 * @param callback
 * @param params
 * @param excludeKeys
 * @param includeKeys
 * @returns
 */
export function paramsValidater<
  C extends Context,
  T,
  P,
  E extends unknown[],
  I extends string[],
>(
  ctx: C,
  callback: (p?: P) => Promise<T>,
  params: P,
  excludeKeys?: E,
  includeKeys?: I,
): Promise<T> {
  return new Promise(async (resolve, reject) => {
    const requiredParams =
      includeKeys ??
      Object.keys(ctx.model.rawAttributes).filter(
        (k) => !['id', 'create_at'].includes(k),
      )

    for (const key of requiredParams) {
      const value = params[key]
      if (
        (value === undefined || value === null) &&
        !excludeKeys?.includes(key)
      ) {
        ctx.body.ResponseMetadata.Error = {
          Code: 400,
          Msg: `Error reason: ${key} is required.`,
        }
        reject(null)
        break
      }
    }

    try {
      const res = await callback(params)
      resolve(res)
    } catch (e: any) {
      ctx.body.ResponseMetadata.Error = generateErrorReason(e.toString())
      reject(null)
    }
  })
}
